/**
 *
 * Creator: jmdvirus
 */

#include <sys/prctl.h>
#include "utils/rt_print.h"
#include "cm_service_base.h"

static const char *s_section = "servicebase";
static const char *s_sub = "run";

CMServiceBaseInterface::CMServiceBaseInterface(const char *name_)
{
    name = name_;
    pid = 0;
    exited = false;
    status = SERVICE_BASE_ST_NONE;
}

CMServiceBaseInterface::~CMServiceBaseInterface()
{
}

void *threadServiceBaseRun(void *args)
{
    prctl(PR_SET_NAME, "serviceBaseThread");

    rtinfo("[%s][%s] service base thread start", s_section, s_sub);
    CMServiceBaseInterface *sb = (CMServiceBaseInterface*)args;
    if (sb && !sb->exited)
    {
        sb->run();
    }
    rtinfo("[%s][%s] service base thread stop", s_section, s_sub);

    return NULL;
}

int CMServiceBaseInterface::start()
{
    if (pid > 0)
    {
        setStatus(SERVICE_BASE_ST_STARTED);
        return 0;
    }
    setStatus(SERVICE_BASE_ST_STARTING);
    exited = false;
    int ret = pthread_create(&pid, NULL, threadServiceBaseRun, this);
    if (ret < 0)
    {
        rterror("[%s][%s] create thread fail ret=[%d]", s_section, s_sub, ret);
        exited = true;
        setStatus(SERVICE_BASE_ST_STOPPED);
        return ret;
    }
    rterror("[%s][%s] create thread success", s_section, s_sub);
    setStatus(SERVICE_BASE_ST_STARTED);
    return 0;
}

int CMServiceBaseInterface::stop()
{
    setStatus(SERVICE_BASE_ST_STOPPING);
    exited = true;
    pthread_join(pid, NULL);
    setStatus(SERVICE_BASE_ST_STOPPED);
    rterror("[%s][%s] thread exit, clear all", s_section, s_sub);
    clear();
    return 0;
}

int CMServiceBaseInterface::getStatus()
{
    return status;
}

void CMServiceBaseInterface::setStatus(int st)
{
    rterror("[%s][%s] status o=[%d] => n=[%d]", s_section, s_sub,
            status, st);

    status = st;

    notify(status, NULL);
}

int CMServiceBaseInterface::registerNotify(int type, cm_service_base_notify_cb notify)
{
    if (!notify)
    {
        return -1;
    }
    rtinfo( "[%s][%s] register type=[%d] notify=[%p]", s_section, s_sub, type, notify);
    lock.lock(__func__, __LINE__);

    auto iter = cNotifyList.find(type);
    if (iter == cNotifyList.end())
    {
        // 创建一个新的
        cNotifyList[type].push_back(notify);
    }
    else
    {
        bool find = false;
        for (auto iter = cNotifyList[type].begin();
             iter != cNotifyList[type].end(); iter++)
        {
            if (*iter == notify)
            {
                find = true;
                break;
            }
        }
        if (!find)
        {
            cNotifyList[type].push_back(notify);
        }
    }

    size_t size = cNotifyList[type].size();

    lock.unlock();
    return size;
}

int CMServiceBaseInterface::registerNotify(int type, CMServiceBaseFunction *func)
{
    if (!func)
    {
        return -1;
    }
    rtinfo("[%s][%s] register type=[%d] func=[%p]", s_section, s_sub, type, func);
    lock.lock(__func__, __LINE__);

    auto iter = cppNotifyList.find(type);
    if (iter == cppNotifyList.end())
    {
        // 创建一个新的
        cppNotifyList[type].push_back(func);
    }
    else
    {
        bool find = false;
        for (auto iter = cppNotifyList[type].begin();
             iter != cppNotifyList[type].end(); iter++)
        {
            if (*iter == func)
            {
                find = true;
                break;
            }
        }
        if (!find)
        {
            cppNotifyList[type].push_back(func);
        }
    }

    size_t size = cppNotifyList[type].size();

    lock.unlock();
    return size;
}

int CMServiceBaseInterface::unregisterNotify(int type, cm_service_base_notify_cb notify)
{
    rtinfo("[%s][%s] unregister type=[%d] notify=[%p]", s_section, s_sub, type, notify);

    lock.lock(__func__, __LINE__);

    auto iter = cNotifyList.find(type);
    if (iter != cNotifyList.end())
    {
        for (auto iter = cNotifyList[type].begin();
             iter != cNotifyList[type].end(); iter++)
        {
            if (*iter == notify)
            {
                cNotifyList[type].erase(iter);
                break;
            }
        }
    }
    else
    {
        return -2;
    }

    size_t size = cNotifyList[type].size();

    lock.unlock();
    return size;
}

int CMServiceBaseInterface::unregisterNotify(int type, CMServiceBaseFunction *func)
{
    rtinfo("[%s][%s] unregister type=[%d] notify=[%p]", s_section, s_sub, type, func);
    lock.lock(__func__, __LINE__);

    auto iter = cppNotifyList.find(type);
    if (iter != cppNotifyList.end())
    {
        for (auto iter = cppNotifyList[type].begin();
             iter != cppNotifyList[type].end(); iter++)
        {
            if (*iter == func)
            {
                cppNotifyList[type].erase(iter);
                break;
            }
        }
    }
    else
    {
        return -2;
    }

    size_t size = cppNotifyList[type].size();

    lock.unlock();
    return size;
}

void CMServiceBaseInterface::clear()
{
    lock.lock(__func__, __LINE__);

    for (auto &iter : cNotifyList)
    {
        iter.second.clear();
    }
    for (auto &iter : cppNotifyList)
    {
        iter.second.clear();
    }

    lock.unlock();
}

int CMServiceBaseInterface::notify(int type, void *args)
{
    for (auto &iter : cNotifyList)
    {
        if (iter.first == type)
        {
            for (auto &iter1 : iter.second)
            {
                (*iter1)(type, args);
            }
        }
    }
    for (auto &iter : cppNotifyList)
    {
        if (iter.first == type)
        {
            for (auto &iter1 : iter.second)
            {
                (*iter1).notify(type, args);
            }
        }
    }
    return 0;
}

int CMServiceBaseInterface::privNotify(int type, void *args)
{
    return notify(type, args);
}
